package com.lezheba.db;

import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

public class Dao {
	static Logger logger = Logger.getLogger(Dao.class.getName());

	protected SessionFactory sessionFactory = null;

	protected Session session = null;
	protected Transaction transaction = null;

	protected boolean selfManagedTransaction = false;
	private static Dao dao;

	public static Dao getInstance() {
		if (dao == null) {
			dao = new Dao();
			dao.selfManagedTransaction = true;
			dao.init();
		}
		return dao;
	}

	private void init() {
		sessionFactory = HibernateUtil.getSessionFactory();
		logger.info("Dao successfully initialized");
	}

	public void save(Object object) {
		try {
			beforeHibernateCall();

			session.save(object);

			afterHibernateCall();
		} catch (HibernateException e) {
			logger.error("HibernateException: " + e.toString());
		}
	}

	public void update(Object object) {
		try {
			beforeHibernateCall();

			session.update(object);

			afterHibernateCall();
		} catch (HibernateException e) {
			logger.error("HibernateException: " + e.toString());
		}
	}
	
	public void saveOrUpdate(Object object) {
		try {
			beforeHibernateCall();

			session.saveOrUpdate(object);

			afterHibernateCall();
		} catch (HibernateException e) {
			logger.error("HibernateException: " + e.toString());
		}
	}
	
	@SuppressWarnings("rawtypes")
	public List getListByHql(String hql, Object[] paras) {
		Query query = getSession().createQuery(hql);
		for (int i = 0; i < paras.length; i++) {
			query.setParameter(i, paras[i]);
		}
		return query.list();
	}

	@SuppressWarnings("rawtypes")
	public List getList(String sql, Object[] paras) {
		SQLQuery query = getSession().createSQLQuery(sql);
		for (int i = 0; i < paras.length; i++) {
			query.setParameter(i, paras[i]);
		}
		return query.list();
	}

	@SuppressWarnings("rawtypes")
	public Object getObject(String sql, Object[] paras) {
		List list = getList(sql, paras);
		if (list.size() > 0) {
			return list.get(0);
		}
		return null;
	}
	
	@SuppressWarnings("rawtypes")
	public Object getObjectByHql(String hql, Object[] paras) {
		List list = getListByHql(hql, paras);
		if (list.size() > 0) {
			return list.get(0);
		}
		return null;
	}
	
	@SuppressWarnings("rawtypes")
	public List getListByHql(String hql, Object para) {
		return getListByHql(hql, new Object[]{para});
	}

	@SuppressWarnings("rawtypes")
	public List getList(String sql, Object para) {
		return getList(sql, new Object[]{para});
	}

	public Object getObject(String sql, Object para) {
		return getObject(sql, new Object[]{para});
	}

	public Object getObjectByHql(String hql, Object para) {
		return getObjectByHql(hql, new Object[]{para});
	}

	public boolean isSelfManagedTransaction() {
		return selfManagedTransaction;
	}

	public void setSelfManagedTransaction(boolean selfManagedTransaction) {
		this.selfManagedTransaction = selfManagedTransaction;
	}

	public Session getManagingSession() throws HibernateException {
		if (selfManagedTransaction) {
			throw new HibernateException(
					"Cannot getManagingSession() for a selfManagedTransaction-Dao ");
		}
		if (session == null) {
			if (sessionFactory != null) {
				session = sessionFactory.openSession();
			} else {
				logger.fatal("no sessionFactory found; check Hibernate instantiation/configuration");
			}

		}
		return session;
	}

	protected Session getSession() throws HibernateException {
		session = sessionFactory.openSession();
		if (session == null && selfManagedTransaction) {
			session = sessionFactory.openSession();
		} else if (session == null) {
			throw new HibernateException(
					"selfManagedTransaction = false; please inject session");
		}
		return session;
	}

	protected void beforeHibernateCall() throws HibernateException {
		if (isSelfManagedTransaction()) {
			session = sessionFactory.openSession();
			transaction = session.beginTransaction();
		} else {
			session = getSession();
		}
	}

	protected void afterHibernateCall() throws HibernateException {
		if (isSelfManagedTransaction()) {
			transaction.commit();
			session.flush();
			session.disconnect();
			session.close();
		}
	}

	protected void rollbackAndClose() {
		if (isSelfManagedTransaction()) {
			try {
				transaction.rollback();
				session.flush();
				session.disconnect();
				session.close();
			} catch (HibernateException hibernateException) {
				logger.error("Could not rollbackAndClose()");
			}
		}
	}
}
